package com.mxw.rulesengine.config;

import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.exc.InvalidFormatException;
import com.mxw.commons.errorcode.GlobalErrorCode;
import com.mxw.commons.exception.CustomException;
import com.mxw.commons.restful.Result;
import com.mxw.commons.utils.CustomExceptionUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.text.MessageFormat;
import java.util.Set;

/** @Description: 全局异常处理 @Author: RingKo */
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
  /** @Description: 参数校验异常处理 */
  @ExceptionHandler({
      MethodArgumentNotValidException.class,
      HttpMessageNotReadableException.class,
      MethodArgumentTypeMismatchException.class,
      MissingServletRequestParameterException.class,
      ConstraintViolationException.class,
      HttpRequestMethodNotSupportedException.class
  })
  public Result<Object> parameterVerificationHandler(Exception e) {
    // 不支持的请求方式
    if (e instanceof HttpRequestMethodNotSupportedException) {
      String method = ((HttpRequestMethodNotSupportedException) e).getMethod();
      String msg = MessageFormat.format("不支持{0}请求", method);
      log.error(GlobalErrorCode.REQUEST_METHOD_NOT_SUPPORTED.getLogString(msg), e);
      return Result.respondWithIErrorCode(GlobalErrorCode.REQUEST_METHOD_NOT_SUPPORTED, msg);
    }
    // 参数校验POST
    if (e instanceof MethodArgumentNotValidException) {
      FieldError fieldError =
          ((MethodArgumentNotValidException) e).getBindingResult().getFieldErrors().get(0);
      String msg = MessageFormat.format("请求参数错误：{0}", fieldError.getDefaultMessage());
      log.error(GlobalErrorCode.INVALID_PARAMETER.getLogString(msg), e);
      return Result.respondWithIErrorCode(GlobalErrorCode.INVALID_PARAMETER, msg);
    }
    // 参数校验POST
    if (e instanceof HttpMessageNotReadableException) {
      Throwable cause = e.getCause();
      if (cause instanceof InvalidFormatException) {
        StringBuilder sb = new StringBuilder();
        ((InvalidFormatException) cause)
            .getPath()
            .forEach(item -> sb.append(item.getFieldName()).append("、"));
        sb.deleteCharAt(sb.length() - 1);
        sb.append("数据类型不匹配");
        String msg = MessageFormat.format("请求参数错误：{0}", sb);
        log.error(GlobalErrorCode.INVALID_PARAMETER.getLogString(msg), e);
        return Result.respondWithIErrorCode(GlobalErrorCode.INVALID_PARAMETER, msg);
      }
      if (cause instanceof JsonParseException) {
        String msg = "错误的json格式";
        log.error(GlobalErrorCode.INVALID_PARAMETER.getLogString(msg), e);
        return Result.respondWithIErrorCode(GlobalErrorCode.INVALID_PARAMETER, msg);
      }
      String msg = "参数数值不符合要求";
      log.error(GlobalErrorCode.INVALID_PARAMETER.getLogString(msg), e);
      return Result.respondWithIErrorCode(GlobalErrorCode.INVALID_PARAMETER, msg);
    }
    // 参数校验GET
    if (e instanceof MethodArgumentTypeMismatchException) {
      MethodArgumentTypeMismatchException exception = (MethodArgumentTypeMismatchException) e;
      String msg = MessageFormat.format("请求参数错误：{0}数据类型不匹配", exception.getName());
      log.error(GlobalErrorCode.INVALID_PARAMETER.getLogString(msg), e);
      return Result.respondWithIErrorCode(GlobalErrorCode.INVALID_PARAMETER, msg);
    }
    // 参数校验GET
    if (e instanceof MissingServletRequestParameterException) {
      MissingServletRequestParameterException exception =
          (MissingServletRequestParameterException) e;
      String msg = MessageFormat.format("缺少参数：{0}", exception.getParameterName());
      log.error(GlobalErrorCode.INVALID_PARAMETER.getLogString(msg), e);
      return Result.respondWithIErrorCode(GlobalErrorCode.INVALID_PARAMETER, msg);
    }
    // 参数校验GET
    if (e instanceof ConstraintViolationException) {
      StringBuilder sb = new StringBuilder();
      sb.append("请求参数错误：");
      ConstraintViolationException exception = (ConstraintViolationException) e;
      Set<ConstraintViolation<?>> violations = exception.getConstraintViolations();
      for (ConstraintViolation<?> item : violations) {
        sb.append(item.getMessage()).append(",");
      }
      sb.deleteCharAt(sb.length() - 1);
      String msg = sb.toString();
      log.error(GlobalErrorCode.INVALID_PARAMETER.getLogString(msg), e);
      return Result.respondWithIErrorCode(GlobalErrorCode.INVALID_PARAMETER, msg);
    }
    log.error(GlobalErrorCode.SYSTEM_ERROR.getLogString(null), e);
    return Result.respondWithIErrorCode(GlobalErrorCode.SYSTEM_ERROR);
  }

  /** @Description: 自定义业务异常处理 */
  @ExceptionHandler(CustomException.class)
  public Result<Object> customExceptionHandler(CustomException e) {
    log.error(e.getLogString(null), e);
    boolean whetherHideCustomErrorMessage = CustomExceptionUtil.whetherHideCustomErrorMessage(e);
    if (whetherHideCustomErrorMessage) {
      return Result.respond(e.getCodeId(), GlobalErrorCode.SYSTEM_ERROR.getMsg(), null);
    }
    return Result.respondWithCustomException(e);
  }

  /** @Description: 其他异常处理 */
  @ExceptionHandler(Exception.class)
  public Result<Object> otherExceptionHandler(Exception e) {
    log.error(GlobalErrorCode.SYSTEM_ERROR.getLogString(null), e);
    return Result.respondWithIErrorCode(GlobalErrorCode.SYSTEM_ERROR);
  }
}
